﻿// -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	SmartLib
//  File name:	XmlExts.cs
//  Developer:	Igor Solomatov
//  Created:	06.03.2013
// 
// -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace Smart
{
	public static class XmlExts
	{
		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="name"/>, if not exists returns <paramref name="defaultValue"/>
		/// </summary>
		public static string SafeGetAttribute(this XmlNode node, string name, string defaultValue)
		{
			var attributes = node.Attributes;

			if (attributes == null)
				return defaultValue;

			for (int i = 0, iMax = attributes.Count; i < iMax; i++)
			{
				var attribute = attributes[i];

				if (attribute != null && attribute.Name.EqIC(name))
					return attribute.Value;
			}

			return defaultValue;
		}

		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="name"/>, if not exists returns <paramref name="defaultValue"/>
		/// </summary>
		public static string SafeGetAttribute(this XElement node, string name, string defaultValue)
		{
			var attribute = node.Attributes().FirstOrDefault(xAttribute => xAttribute.Name.LocalName.EqIC(name));

			return attribute != null ? attribute.Value : defaultValue;
		}

		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="name"/>, if not exists returns null
		/// </summary>
		public static void SafeGetAttributes(this XElement node, string name1, out string value1, string name2, out string value2)
		{
			var found = 0;

			value1 = null;
			value2 = null;

			foreach (var xAttribute in node.Attributes())
			{
				var name = xAttribute.Name.LocalName;

				if (name.EqIC(name1))
				{
					value1 = xAttribute.Value;
					name1 = null; // much faster string comparision
					if (++found >= 2) return;
				}
				else if (name.EqIC(name2))
				{
					value2 = xAttribute.Value;
					name2 = null; // much faster string comparision
					if (++found >= 2) return;
				}
			}
		}

		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="name"/>, if not exists returns null
		/// </summary>
		public static void SafeGetAttributes(this XElement node, string name1, out string value1, string name2, out string value2, string name3, out string value3)
		{
			var found = 0;

			value1 = null;
			value2 = null;
			value3 = null;

			foreach (var xAttribute in node.Attributes())
			{
				var name = xAttribute.Name.LocalName;

				if (name.EqIC(name1))
				{
					value1 = xAttribute.Value;
					name1 = null; // much faster string comparision
					if (++found >= 3) return;
				}
				else if (name.EqIC(name2))
				{
					value2 = xAttribute.Value;
					name2 = null; // much faster string comparision
					if (++found >= 3) return;
				}
				else if (name.EqIC(name3))
				{
					value3 = xAttribute.Value;
					name3 = null; // much faster string comparision
					if (++found >= 3) return;
				}
			}
		}


		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="name"/>, if not exists returns null
		/// </summary>
		public static void SafeGetAttributes(this XElement node, string name1, out string value1, string name2, out string value2, string name3, out string value3, string name4, out string value4)
		{
			var found = 0;

			value1 = null;
			value2 = null;
			value3 = null;
			value4 = null;

			foreach (var xAttribute in node.Attributes())
			{
				var name = xAttribute.Name.LocalName;

				if (name.EqIC(name1))
				{
					value1 = xAttribute.Value;
					name1 = null; // much faster string comparision
					if (++found >= 4) return;
				}
				else if (name.EqIC(name2))
				{
					value2 = xAttribute.Value;
					name2 = null; // much faster string comparision
					if (++found >= 4) return;
				}
				else if (name.EqIC(name3))
				{
					value3 = xAttribute.Value;
					name3 = null; // much faster string comparision
					if (++found >= 4) return;
				}
				else if (name.EqIC(name4))
				{
					value4 = xAttribute.Value;
					name4 = null; // much faster string comparision
					if (++found >= 4) return;
				}
			}
		}

		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="names"/>, if not exists returns null
		/// </summary>
		public static string[] SafeGetAttributes(this XElement node, params string[] names)
		{
			var found = 0;

			var namesCount = names.Length;
			var processingNames = new string[namesCount];
			var res = new string[namesCount];

			names.CopyTo(processingNames, 0);

			foreach (var xAttribute in node.Attributes())
			{
				var attributeName = xAttribute.Name.LocalName;

				for (int i = 0, iMax = namesCount; i < iMax; i++)
				{
					if (processingNames[i].EqIC(attributeName))
					{
						res[i] = xAttribute.Value;
						processingNames[i] = null; // much faster string comparision
						if (++found >= namesCount) return res;
					}
				}
			}

			return res;
		}

		/// <summary>
		/// Returns <paramref name="node"/>'s attribute value by <paramref name="names"/>, if not exists returns null
		/// </summary>
		public static string[] SafeGetAttributes(this XElement node, IEnumerable<string> names)
		{
			var found = 0;

			var processingNames = names.ToArray();

			var namesCount = processingNames.Length;
			var res = new string[namesCount];

			foreach (var xAttribute in node.Attributes())
			{
				var attributeName = xAttribute.Name.LocalName;

				for (int i = 0, iMax = namesCount; i < iMax; i++)
				{
					if (processingNames[i].EqIC(attributeName))
					{
						res[i] = xAttribute.Value;
						processingNames[i] = null; // much faster string comparision
						if (++found >= namesCount) return res;
					}
				}
			}

			return res;
		}

		/// <summary>
		/// Set <paramref name="node"/>'s attribute <paramref name="value"/> by <paramref name="name"/>
		/// </summary>
		/// <exception cref="InvalidOperationException">Specified node has no Attributes collection!</exception>
		/// <exception cref="InvalidOperationException">OwnerDocument is null!</exception>
		public static void SafeSetAttribute(this XmlNode node, string name, string value)
		{
			var attributes = node.Attributes;

			if (attributes == null)
				throw new InvalidOperationException("Specified node has no Attributes collection!");

			for (int i = 0, iMax = attributes.Count; i < iMax; i++)
			{
				var attribute = attributes[i];

				if (attribute.Name.EqIC(name))
				{
					attribute.Value = value;
					return;
				}
			}

			var doc = node.OwnerDocument;

			if (doc == null)
				throw new InvalidOperationException("OwnerDocument is null!");

			var newAttribute = doc.CreateAttribute(name);

			newAttribute.Value = value;

			attributes.Append(newAttribute);
		}
	}
}